package Fishbowl_test;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Random;
import java.util.ArrayList;
import java.util.Scanner;

public class Fishbowl {
	private int M, N;
	private int [][]fishbowl;
	ArrayList<Fish> fish;
	public static Random gen;	
	private int score;
	private boolean gameOver;
	public static final int [][]directions = {{-1, -1}, {-1, 0}, {-1, 1}, {0, -1}, {0, 1}, {1, -1}, {1, 0}, {1, 1}};

	public Fishbowl(int M, int N, int X, int Y, int RA, int MA, int RB, int MB, int seed) {
		if(M <= 0 || N <= 0)
			throw new IllegalArgumentException("Invalid dimensions for fishbow");
		if(X < 0 || Y < 0)
			throw new IllegalArgumentException("Invalid fish quantities");
		if(M * N < X + Y)
			throw new IllegalArgumentException("Fishbow smaller than necessary");
		
		if(RA <= 0 || RB <= 0)	// bug condição nao existia antes testRANegative
			throw new IllegalArgumentException("Invalid RA or RB");
		if(MA <= 0 || MB <= 0)  // bug condição nao existia antes testRANegative
			throw new IllegalArgumentException("Invalid MA or MB");
		
		this.gameOver = false;
		this.score = 0;
		this.M = M;
		this.N = N;
		this.fish = new ArrayList<Fish>();
		this.fishbowl = new int[this.M][this.N];
		FishA.minToReproduce = RA;
		FishA.maxToDie = MA;
		FishB.minToReproduce = RB;
		FishB.maxToDie = MB;
		Fish.fishbowl = this;
		gen = new Random(seed);
		for(int i = 0; i < X; i++) {
			int x, y;
			do {
				x = gen.nextInt(M);
				y = gen.nextInt(N);
			} while(fishbowl[x][y] != 0);
			fishbowl[x][y] = 1;
			fish.add(new FishA(x, y));
		}
		
		for(int i = 0; i < Y; i++) {
			int x, y;
			do {
				x = gen.nextInt(M);
				y = gen.nextInt(N);
				
			} while(fishbowl[x][y] != 0);
			fishbowl[x][y] = -1;
			fish.add(new FishB(x, y));
		}
	}
	
	public int getNumberOfFish(int type) {
		int A = 0, B = 0;
		for (Fish f  : fish)
			if (f instanceof FishA) {
				A++;				
			} else {
				B++;
			}
		if(type == 1) 
			return A;
		if(type == -1) 
			return B;
		else 
			return A + B;
	}
	
	public Fishbowl(String filename) throws FileNotFoundException {
		int total_fish;
		Scanner scanner = new Scanner(new File(filename));
		this.M = scanner.nextInt();
		this.N = scanner.nextInt();
		if(M <= 0 || N <= 0) {
			scanner.close();
			throw new IllegalArgumentException("Invalid dimensions for fishbow");
		}
		total_fish = scanner.nextInt();
		// Era < apenas... testLoadInvalidFishQuant
		if(total_fish <= 0) {
			scanner.close();
			throw new IllegalArgumentException("Invalid fish quantities");
		}
		if(M * N < total_fish) {
			scanner.close();
			throw new IllegalArgumentException("Fishbow smaller than necessary");
		}

		FishA.minToReproduce = scanner.nextInt();
		FishA.maxToDie = scanner.nextInt();
		FishB.minToReproduce = scanner.nextInt();
		FishB.maxToDie = scanner.nextInt();
		gen = new Random(scanner.nextInt());
		this.score = scanner.nextInt();
		
		this.gameOver = false;
		this.fish = new ArrayList<Fish>();
		this.fishbowl = new int[this.M][this.N];
		
		Fish.fishbowl = this;
		
		for(int i = 0; i < total_fish; i++) {
			int x, y, type;
			x = scanner.nextInt();
			y = scanner.nextInt();
			type = scanner.nextInt();
			fishbowl[x][y] = type;
			if(type == 1)
				fish.add(new FishA(x, y));
			else if(type == -1)
				fish.add(new FishB(x, y));
			fish.get(i).setFood(scanner.nextInt());
			fish.get(i).setStarvation(scanner.nextInt());
		}
		scanner.close();
	}
	
	public void saveGame(String filename) throws IOException {
		FileWriter fw = new FileWriter(filename);
		fw.write(this.M + " " + this.N + " " + this.fish.size() + "\n");
		fw.write(FishA.minToReproduce + " " + FishA.maxToDie + " " + FishB.minToReproduce + " " + FishB.maxToDie + "\n");
		fw.write(Fishbowl.gen.nextInt() + "\n");
		fw.write(this.score + "\n");
		int type;
		for(int i = 0; i < fish.size(); i++) {
			Fish f = fish.get(i);
			if(f instanceof FishA) 
				type = 1;
			else
				type = -1;
			// bug testMlimit estava sem condição if(f.isAlive())
			if(f.isAlive())
				fw.write(f.getX() + " " + f.getY() + " " + type + " " +f.getFood() + " " + f.getStarvation() + "\n");
		}
		fw.close();
	}
	
	public void playGame(int rounds, String filename) throws IOException {
		showFishbowl();
		if(!this.gameOver) //bug score 1 para zero peixes b testYZero
			while(this.score < rounds || rounds == -1) {
				simulateOneStep();
				showFishbowl();
				if(this.gameOver)
					break;
			}
		System.out.println("Score: " + this.score);
		if(filename != null) {
			System.out.println("Saving game");
			saveGame(filename);
		}
	}

	public void simulateOneStep() {
		ArrayList<Fish> newFish = new ArrayList<Fish>();
		for(int i = 0; i < fish.size(); i++) {
			fish.get(i).simulate();
			if(fish.get(i).isAlive())
				newFish.add(fish.get(i));
		}		
		this.score++;
		fish = newFish;
	}
	
	public char getValue(int value) {
		switch(value) {
			case 1:
				return 'A';
			case -1:
				this.gameOver = false;
				return 'B';
			case 0:
				return '-';
			default:
				throw new IllegalArgumentException("Unknown element inside fishbowl");
		}
	}
	
	public void showFishbowl() {
		this.gameOver = true;
		for(int i = 0; i < M; i++) {
			for(int j = 0; j < N; j++) {
				System.out.print(' ');
				System.out.print(getValue(this.fishbowl[i][j]));
				System.out.print(' ');
			}
			System.out.print('\n');
		}
	}
	
	public String toString() {
		String fbString = new String();
		this.gameOver = true;
		for(int i = 0; i < M; i++) {
			for(int j = 0; j < N; j++) {
				fbString += " ";
				fbString += getValue(this.fishbowl[i][j]);
				fbString += " ";
			}
			fbString += '\n';
		}
		for(int i = 0; i < fish.size(); i++) {
			Fish f = fish.get(i);
			if(f.isAlive()) {
				fbString += "(" + f.getX() + ", " + f.getY() + ", " + f.getFood() + ", " + f.getStarvation() + ")\n"; 
			}
		}
		fbString += this.score + "\n";
		return fbString;
	}
	
	public void addNewFish(Fish fish) {
		this.fish.add(fish);
	}

	public ArrayList<Integer> getNeighborhood(int x, int y, int option) {
		ArrayList<Integer> neighbors = new ArrayList<Integer>();
		

		for(int i = 0; i < 8; i++)
                        if(x + directions[i][0] >= 0 && x + directions[i][0] < this.M &&
                                y + directions[i][1] >= 0 && y + directions[i][1] < this.N &&
                                        this.fishbowl[x + directions[i][0]][y + directions[i][1]] == option) {
                        			neighbors.add(i);
			}
		return neighbors;
	}

	public void setCell(int x, int y, int option) {
		this.fishbowl[x][y] = option;		
	}	
	
	public int getCell(int x, int y) {
		return this.fishbowl[x][y];
	}
	
//	public static void main(String[] args) {
//		Fishbowl fishbowl = null;
//		int rounds = -1;
//		String filename = null;
//		
//		
//		if(args.length == 10 || args.length == 11) { // Read parameters from command line
//			fishbowl = new Fishbowl(Integer.valueOf(args[0]), Integer.valueOf(args[1]), Integer.valueOf(args[2]), Integer.valueOf(args[3]), 
//					Integer.valueOf(args[4]), Integer.valueOf(args[5]), Integer.valueOf(args[6]), Integer.valueOf(args[7]), Integer.valueOf(args[8]));
//			rounds = Integer.valueOf(args[9]);
//			if(args.length == 11)
//				filename = args[10];
//		} else if(args.length == 2 || args.length == 3) { // Read parameters and fishbowl from file
//			try {
//				fishbowl = new Fishbowl(args[0]);
//				rounds = Integer.valueOf(args[1]);
//				if(args.length == 3)
//					filename = args[2];
//			} catch (FileNotFoundException e) {
//				System.out.println("File " + args[0] + " not found!");
//				System.exit(-1);
//			}			
//		} else {
//			System.out.println("How to play:\njava Fishbowl M N X Y RA MA RB MB seed\nor java Fishbowl filename");
//			System.exit(0);
//		}
//		try {
//			fishbowl.playGame(rounds, filename);
//		} catch (IOException e) {
//			System.out.println("Can't save game on file " + filename + " !\n");
//		}		
//	}
}
